﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace Web.Extension
{
    /// <summary>
    /// Swagger文档扩展方法
    /// </summary>
    public static class SwaggerExtension
    {
        public static IServiceCollection AddSwaggerService(this IServiceCollection services)
        {
            var apiInfo = new OpenApiInfo
            {
                Title = "Fast系统API接口",
                Version = "v1",
                Contact = new OpenApiContact { Name = "girg@163.com", Email = "girg@163.com", Url = new System.Uri("https://haolaoshiya.com/apidoc") }//跳转到swagger 原生UI
            };
            #region 注册Swagger服务
            services.AddSwaggerGen(c =>
            {
                c.SchemaFilter<IgnoreReadOnlySchemaFilter>();
                //c.RequestBodyFilter<IgnoreReadOnlyRequestBodyFilter>();
                //启用注解对于readonly
                c.EnableAnnotations(true,true);//启用注解https://github.com/domaindrivendev/Swashbuckle.AspNetCore#swashbuckleaspnetcoreannotations
                c.SwaggerDoc("v1", apiInfo);
                #region 忽略过时特性
                //忽略标记过时的Action
                //c.IgnoreObsoleteActions();
                //忽略标记过时的Properties
                //c.IgnoreObsoleteProperties();
                #endregion
                //添加注释服务
                //为 Swagger JSON and UI设置xml文档注释路径
                //获取应用程序所在目录(绝对路径，不受工作目录影响，建议采用此方法获取路径使用windwos&Linux）
                var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
                var apiXmlPath = Path.Combine(basePath, @"ApiWebDoc.xml");//控制器层注释
                var entityXmlPath = Path.Combine(basePath, @"ApiModelDoc.xml");//实体注释
                var commonXmlPath = Path.Combine(basePath, @"ApiCommonDoc.xml");//实体注释
                c.IncludeXmlComments(apiXmlPath, true);//true表示显示控制器注释
                c.IncludeXmlComments(entityXmlPath, true);
                c.IncludeXmlComments(commonXmlPath, true);

                //添加控制器注释
                //c.DocumentFilter<SwaggerDocTag>();

                //添加header验证信息
                //c.OperationFilter<SwaggerHeader>();
                //var security = new Dictionary<string, IEnumerable<string>> { { "Bearer", new string[] { } }, };

                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Description = "文本框里输入从服务器获取的Token。格式为：Bearer + 空格+token",//JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"
                    Name = "Authorization",////jwt默认的参数名称
                    In = ParameterLocation.Header,////jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey,
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    { new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference()
                        {
                            Id = "Bearer",
                            Type = ReferenceType.SecurityScheme
                        }
                    }, Array.Empty<string>() }
                });
            });
            #endregion

            return services;
        }

        public static void UseSwaggerService(this IApplicationBuilder app)
        {
            //在 Startup.Configure 方法中，启用中间件为生成的 JSON 文档和 Swagger UI 提供服务：
            // Enable middleware to serve generated Swagger as a JSON endpoint.
            app.UseSwagger();

            // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
            // specifying the Swagger JSON endpoint.
            //启用原生自带 UI
            //https://github.com/domaindrivendev/Swashbuckle.AspNetCore#swashbuckleaspnetcoreredoc            
            app.UseSwaggerUI(c =>
            {
                c.DocumentTitle = "Fast系统API";
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "API接口 V1");
                c.RoutePrefix = "apidoc";
                //c.InjectStylesheet("/swagger-ui/custom.css");
            });
            //启用redoc UI
            //https://www.cnblogs.com/xitianqujing/p/13902957.html
            //https://github.com/domaindrivendev/Swashbuckle.AspNetCore#swashbuckleaspnetcoreredoc
            //https://github.com/Redocly/redoc
            app.UseReDoc(c =>
            {
                c.RoutePrefix = string.Empty;
                c.SpecUrl = $"swagger/v1/swagger.json";
                c.DocumentTitle = "Fast系统API";
                c.ConfigObject = new Swashbuckle.AspNetCore.ReDoc.ConfigObject
                {
                    //NoAutoAuth = false,
                    HideDownloadButton = true,
                    //HideLoading = false,
                    //HideHostname = true,
                    RequiredPropsFirst = true,
                    //DisableSearch = true,
                    //NativeScrollbars = true,
                    AdditionalItems = new Dictionary<string, object>
                    {
                        {"pathInMiddlePanel",true },
                        { "theme",new Dictionary<string,object>{
                            { "rightPanel",new Dictionary<string, object>
                              {
                                { "width","27%" }
                              }
                            },
                            { "typography",new Dictionary<string, object>
                              {
                                { "fontSize","16px" }
                              }
                            },
                            { "menu",new Dictionary<string, object>
                              {
                                { "width","285px" }
                              }
                            }
                        } }
                    }
                };
            });
            #region 支持rapidoc UI 
            //安装 IGeekFan.AspNetCore.RapiDoc
            //https://mrin9.github.io/RapiDoc/index.html
            //参考https://github.com/luoyunchong/IGeekFan.AspNetCore.RapiDoc/blob/master/README.zh-CN.md
            /*
            app.UseRapiDocUI(c =>
            {
                c.RoutePrefix = ""; // serve the UI at root
                c.SwaggerEndpoint("swagger/v1/swagger.json", "API接口 V1");
                c.GenericRapiConfig = new GenericRapiConfig()
                {
                    //RenderStyle = "focused",
                    //Theme = "light", //light,dark,focused   
                    RenderStyle = "read",//read | view | focused
                    Theme = "light",//light | dark
                    SchemaStyle = "table"//tree | table
                };
            });
            */
            #endregion
        }

    }
    /*
    public class IgnoreReadOnlyRequestBodyFilter2 : IRequestBodyFilter
    {
        public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context)
        {
            var openApiMediaType = requestBody.Content.First().Value;
            if (openApiMediaType != null)
            {
                Console.WriteLine("类型:" + openApiMediaType.Schema.Title);
                foreach (var p in openApiMediaType.Schema.Properties)
                {
                    Console.WriteLine("属性:" + p.Key + "-" + p.Value);
                }
                var deprecatedProperties = openApiMediaType.Schema.Properties.Where(p => p.Value.ReadOnly).ToList();
                foreach (var property in deprecatedProperties)
                {
                    openApiMediaType.Schema.Properties.Remove(property);
                }
            }
        }
    }*/
    /// <summary>
    /// 忽略readonly属性。要与c.EnableAnnotations(true,true)配合使用。暂时不知道问题所在
    /// </summary>
    //https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/src/Swashbuckle.AspNetCore.Annotations/AnnotationsSchemaFilter.cs
    //https://blog.csdn.net/qq_21265915/article/details/104070710
    public class IgnoreReadOnlySchemaFilter : ISchemaFilter
    {

        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            //var schemaAttribute = context.Type.GetCustomAttributes<SwaggerSchemaAttribute>() .FirstOrDefault();
            if (schema?.Properties?.Count <= 0)
            {
                return;
            }
            var _Properties = context.Type.GetProperties();//获取属性集合
            foreach (var property in _Properties)
            {
 
                //获取属性上得注解
                SwaggerSchemaAttribute schemaAttribute = property.GetCustomAttributes<SwaggerSchemaAttribute>().FirstOrDefault();
                //Console.WriteLine("属性:" + property+"-"+ schemaAttribute);
                var pname = property.Name.ToLower();
                if (schemaAttribute != null /*&& schema.Properties.ContainsKey(pname)*/)
                {
                    schema.ReadOnly = true;
                   // schema.Properties.Remove(pname);
                }
            };
        }
    }
}
